<?php

namespace api\finance\model;

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;
use WeChatPay\Formatter;

class MoneyChargeModel extends \Aaa\finance\model\MoneyCashModel {

    public $domain;

    public function __construct($user = []) {
        parent::__construct($user);
        $app = app();
        $request = $app->request;
        $scheme = $request->scheme();
        if ($request->server("HTTP_X_CLIENT_SCHEME") == "https") {
            $scheme = "https";
        }
        $this->domain = $scheme . "://" . $request->host(false);
    }

    //支付宝当面付
    public function alipayFaceToFace($param) {
        $amount = abs(round(floatval($param['amount']), 2));
        $id = $this->addRecord($amount, '支付宝充值');
        $siteName = cmf_get_option('system/site')['siteName'];
        $config = cmf_get_option('system/api/alipay');

        $sdkPath = CMF_ROOT . 'vendor/alipay-sdk-PHP-4.9.2/';
        require_once $sdkPath . 'aop/AopCertClient.php';
        $aop = new \AopCertClient();
        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
        $aop->signType = 'RSA2';
        $aop->postCharset = 'UTF-8';
        $aop->format = 'json';
        $aop->appId = $config['appId'];
        $aop->rsaPrivateKey = $config['rsaPrivateKey'];
        $aop->alipayrsaPublicKey = $aop->getPublicKey(CMF_ROOT . $config['alipayCertPublicKey']);
        $aop->appCertSN = $aop->getCertSN(CMF_ROOT . $config['appCertPublicKey']);
        $aop->alipayRootCertSN = $aop->getRootCertSN(CMF_ROOT . $config['alipayRootCert']);

        require_once $sdkPath . 'aop/request/AlipayTradePrecreateRequest.php';
        $request = new \AlipayTradePrecreateRequest  ();
        $request->setNotifyUrl($this->domain . '/api/finance/MoneyChargeNotify/alipay');
        $request->setReturnUrl($this->domain . '/api/finance/MoneyChargeNotify/payReturn');
        $param = [
            'subject' => $siteName . '充值',
            'out_trade_no' => $id,
            'total_amount' => $amount,
            'product_code' => 'FACE_TO_FACE_PAYMENT',
        ];
        $bizcontent = json_encode($param);
        $request->setBizContent($bizcontent);
        $result = $aop->execute($request);
        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
        $resultCode = $result->$responseNode->code;

        if (!empty($resultCode) && $resultCode == 10000) {
            return [
                'qrCode' => $result->$responseNode->qr_code,
                'id' => $id
            ];
        } else {
            $this->v("{$result->$responseNode->msg}: {$result->$responseNode->sub_msg}");
        }
    }

    //支付宝app支付
    public function alipayApp($param) {
        $amount = abs(round(floatval($param['amount']), 2));
        $id = $this->addRecord($amount, '支付宝充值');
        $siteName = cmf_get_option('system/site')['siteName'];
        $config = cmf_get_option('system/api/alipay');

        $sdkPath = CMF_ROOT . 'vendor/alipay-sdk-PHP-4.9.2/';
        require_once $sdkPath . 'aop/AopCertClient.php';
        $aop = new \AopCertClient();
        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
        $aop->signType = 'RSA2';
        $aop->postCharset = 'UTF-8';
        $aop->format = 'json';
        $aop->appId = $config['appId'];
        $aop->rsaPrivateKey = $config['rsaPrivateKey'];
        $aop->alipayrsaPublicKey = $aop->getPublicKey(CMF_ROOT . $config['alipayCertPublicKey']);
        $aop->appCertSN = $aop->getCertSN(CMF_ROOT . $config['appCertPublicKey']);
        $aop->alipayRootCertSN = $aop->getRootCertSN(CMF_ROOT . $config['alipayRootCert']);

        require_once $sdkPath . 'aop/request/AlipayTradeAppPayRequest.php';
        $request = new \AlipayTradeAppPayRequest  ();
        $request->setNotifyUrl($this->domain . '/api/finance/MoneyChargeNotify/alipay');
        if (cmf_get_option('system/api/alipay')['appRechargeMethod'] == 'wap') {
            $request->setReturnUrl($this->domain . '/api/finance/MoneyChargeNotify/payReturnWap');
        } else {
            $request->setReturnUrl($this->domain . '/api/finance/MoneyChargeNotify/payReturn');
        }
        $param = [
            'subject' => $siteName . '充值',
            'out_trade_no' => $id,
            'total_amount' => $amount,
            'product_code' => 'QUICK_MSECURITY_PAY',
        ];
        $bizcontent = json_encode($param);
        $request->setBizContent($bizcontent);
        $orderInfo = $aop->sdkExecute($request);

        return [
            'orderInfo' => $orderInfo,
            'id' => $id
        ];

    }

    //支付宝手机网站支付 获取充值链接
    public function alipayWap($param) {
        $amount = abs(round(floatval($param['amount']), 2));
        $id = $this->addRecord($amount, '支付宝充值');

        $siteName = cmf_get_option('system/site')['siteName'];
        $config = cmf_get_option('system/api/alipay');

        $sdkPath = CMF_ROOT . 'vendor/alipay-sdk-PHP-4.9.2/';
        require_once $sdkPath . 'aop/AopCertClient.php';
        $aop = new \AopCertClient();
        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
        $aop->apiVersion = '1.0';
        $aop->signType = 'RSA2';
        $aop->postCharset = 'UTF-8';
        $aop->format = 'json';
        $aop->appId = $config['appId'];
        $aop->rsaPrivateKey = $config['rsaPrivateKey'];
        $aop->alipayrsaPublicKey = $aop->getPublicKey(CMF_ROOT . $config['alipayCertPublicKey']);
        $aop->appCertSN = $aop->getCertSN(CMF_ROOT . $config['appCertPublicKey']);
        $aop->alipayRootCertSN = $aop->getRootCertSN(CMF_ROOT . $config['alipayRootCert']);

        require_once $sdkPath . 'aop/request/AlipayTradeWapPayRequest.php';
        $request = new \AlipayTradeWapPayRequest  ();
        $request->setNotifyUrl($this->domain . '/api/finance/MoneyChargeNotify/alipay');
        $request->setReturnUrl($this->domain . '/api/finance/MoneyChargeNotify/payReturn');
        $param = [
            'subject' => $siteName . '充值',
            'out_trade_no' => $id,
            'total_amount' => $amount,
            'product_code' => 'QUICK_WAP_WAY',
        ];
        $bizcontent = json_encode($param);
        $request->setBizContent($bizcontent);
        $url = $aop->pageExecute($request, 'GET');
        return [
            'url' => $url,
            'id' => $id
        ];
    }

    //微信支付
    public function wechatpayApp($param) {
        $amount = abs(round(floatval($param['amount']), 2));
        $id = $this->addRecord($amount, '微信充值');
        $siteName = cmf_get_option('system/site')['siteName'];
        $config = cmf_get_option('system/api/wechat');

        require_once(CMF_ROOT . 'vendor/autoload.php');

        // 设置参数

        // 商户号
        $merchantId = $config['mchId'];

        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://' . CMF_ROOT . $config['apiClientKey'];
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);


        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = $config['merchantCertificateSerial'];

        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = 'file://' . CMF_ROOT . $config['cert'];
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        // 从「微信支付平台证书」中获取「证书序列号」
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

        // 构造一个 APIv3 客户端实例
        $instance = Builder::factory([
            'mchid' => $merchantId,
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);

        // 发送请求
        try {
            $resp = $instance->chain('v3/pay/transactions/app')->post([
                'json' => [
                    'mchid' => $merchantId,
                    'out_trade_no' => $id,
                    'appid' => $config['mobileAppId'],
                    'description' => $siteName . '充值',
                    'notify_url' => $this->domain . '/api/finance/MoneyChargeNotify/wechatpay',
                    'amount' => [
                        'total' => $amount * 100,
                        'currency' => 'CNY'
                    ],
                ]
            ]);
        } catch (\Exception $e) {
            // 进行错误处理
            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                $r = json_decode($r->getBody(), true);
                $this->v($r['message']);
            }
        }
        if ($resp->getStatusCode() == 200) {
            $body = json_decode($resp->getBody(), true);
            $param = [
                'appId' => $config['mobileAppId'],
                'timeStamp' => (string)Formatter::timestamp(),
                'nonceStr' => Formatter::nonce(),
                'package' => $body['prepay_id'],
            ];
            $param += [
                'paySign' => Rsa::sign(Formatter::joinedByLineFeed(...array_values($param)), $merchantPrivateKeyInstance),
                'signType' => 'RSA'
            ];
            return [
                'id' => $id,
                'orderInfo' => [
                    'appid' => $config['mobileAppId'],
                    'partnerid' => $merchantId,
                    'prepayid' => $body['prepay_id'],
                    'package' => 'Sign=WXPay',
                    'timestamp' => $param['timeStamp'],
                    'noncestr' => $param['nonceStr'],
                    'sign' => $param['paySign'],
                ]
            ];
        }
    }

    //魔宝支付
    public function mobaopay($param, $payType, $deviceType) {
        $amount = abs(round(floatval($param['amount']), 2));
        $siteName = cmf_get_option('system/site')['siteName'];
        $config = cmf_get_option('system/api/mobaopay');
        //子商户ID microMerchId
        $microMerchId = $config["{$payType}MicroMerchId"];
        $microMerchId = explode("\n", $microMerchId);
        $microMerchId = $microMerchId[rand(0, count($microMerchId) - 1)];
        //支付方式
        $method = [
            'alipay' => [
                'bank' => '支付宝充值',
                'apiName' => 'ALIPAY',
                'notifyAction' => 'mobaopayAlipay',
            ],
            'wechatpay' => [
                'bank' => '微信充值',
                'apiName' => 'WECHAT',
                'notifyAction' => 'mobaopayWxpay',
            ],
        ];
        $method = $method[$payType];
        if ($payType == 'alipay') {
            if ($deviceType == 'pc') {
                $method['payType'] = '121';
                $method['product'] = '120';
            } else {
                $method['payType'] = '173';
                $method['product'] = '170';
            }
        }
        if ($payType == 'wechatpay') {
            if ($deviceType == 'pc') {
                $method['payType'] = '123';
                $method['product'] = '120';
            } else {
                $method['payType'] = '164';
                $method['product'] = '160';
            }
        }
        $id = $this->addRecord($amount, $method['bank']);
        $data = [
            'apiName' => $method['apiName'],//接口名称
            'custNo' => $config['merchant'],//商户号
            'merchTradeNo' => $id,//商户订单号
            'tradeAmt' => $amount,//支付金额
            'goodsName' => $siteName . '充值',//商品名称
            //'goodsDesc' => 'xxx',//商品描述
            'tradeTime' => $this->timeToDate(0, 'YmdHis'),//商户订单创建时间
            'merchUrl' => "{$this->domain}/api/finance/MoneyChargeNotify/{$method['notifyAction']}",//后台通知URL
            'payEnvType' => '1',//支付环境
            'payType' => $method['payType'],//支付方式
            'tradeSummer' => $siteName . '充值',//交易摘要
            'product' => $method['product'],//产品类型
            //'terminalType' => '1',//交易來源
            //'terminalId' => '27.187.174.81',//交易上送IP
            'merchType' => '2',//商户类型
            'microMerchId' => $microMerchId,//小微商户id
        ];
        $data['signMsg'] = $this->mobaopaySign($data);
        //print_r($data);
        $re = $this->post('https://trade2.mobaopay.com/cashier/api/gateway.cgi', $data);
        $re = json_decode($re);
        //print_r($re);
        if ($re->retCode == 1) {
            if ($deviceType == 'pc') {
                $res = [
                    'qrCode' => base64_decode($re->retData->codeUrl),
                    'id' => $id
                ];
            } else {
                $res = [
                    'url' => $re->retData,
                    'id' => $id
                ];
            }
            return $res;
        } else {
            $this->v($re->retMsg);
        }
    }

    //魔宝 签名
    private function mobaopaySign($data) {
        $config = cmf_get_option('system/api/mobaopay');
        $sign = [];
        ksort($data);
        foreach ($data as $k => $v) {
            $sign[] = "$k=$v";
        }
        $sign = implode('&', $sign);
        $key = file_get_contents(CMF_ROOT . $config['merchantCert']);
        if (openssl_pkcs12_read($key, $certs, $config['merchantCertPass'])) {
            if (openssl_sign($sign, $signature, $certs['pkey'], OPENSSL_ALGO_MD5)) {
                openssl_free_key($certs['pkey']);
                $sign = base64_encode($signature);
                return $sign;
            } else $this->v('签名错误');
        } else $this->v('证书或密码错误');
    }

}

